#include <linux/fs.h>
#include <linux/init.h>
#include <linux/cdev.h>
#include <linux/kdev_t.h>
#include <linux/module.h>
#include <linux/device.h>

#define DEVICE_SNAME "schrdev"
#define DEVICE_ANAME "achrdev"

#define DEVICE_CLASS_NAME "chrdev_class"
#define DEVICE_NODE_NAME  "chrdev_test" 

int major_num = 0,minor_num = 0;

struct  cdev cdev = {
    .owner = THIS_MODULE,
};
struct class *class;
struct device *device;

module_param(major_num,int,S_IRUSR);
module_param(minor_num,int,S_IRUSR);

dev_t dev_num = 0;

 int chrdev_open (struct inode *inode, struct file *file){
    printk("chrdev is open\r\n");
    return 0;
 }
 
struct file_operations chrdevFops =
{   
    .owner = THIS_MODULE,
    .open  = chrdev_open,
};

static int chrdevInit(void){
    printk("chrdev init brgin!\r\n");
    int ret = 0;
    if( major_num > 0){
        //手动分配 
        printk("major num:%d\r\n",major_num);
        printk("minor num:%d\r\n",minor_num);
        dev_num = MKDEV(major_num,minor_num);
        ret = register_chrdev_region(dev_num,1,DEVICE_SNAME);
        if(ret < 0){
            printk("register chrdev error!\r\n");
            return -1;
        }
        else {
             printk("register chrdev ok!\r\n");
        }
    }
    else {
        //动态分配
        ret = alloc_chrdev_region(&dev_num,0,1,DEVICE_ANAME);
        if(ret < 0){
            printk("alloc register chrdev fail\r\n");
            return -1;
        }
        else{
            printk("alloc register chrdev ok\r\n");
            printk("major:%d\r\n",MAJOR(dev_num));
            printk("minor:%d\r\n",MINOR(dev_num));
        }
    }
    //自动注册设备节点
    cdev_init(&cdev,&chrdevFops);
    cdev_add(&cdev,dev_num,1);

    class = class_create(THIS_MODULE,DEVICE_CLASS_NAME);

    device = device_create(class, NULL, dev_num, NULL, DEVICE_NODE_NAME);

    return 0;
}

static void chrdevExit(void){
    unregister_chrdev_region(dev_num,1);
    cdev_del(&cdev);
    device_destroy(class,dev_num);
    class_destroy(class);
    printk("chrdev is out\r\n");
}

module_init(chrdevInit);
module_exit(chrdevExit);
MODULE_LICENSE("GPL");
